namespace AnalyStock.DataAnalysis;

public static class CommMathMethod
{
    //计算均值,递推法
    internal static float MeanValue(this IEnumerable<float> samples)
    {
        var mean = 0.0f;
        var n = 0;
        using var enumerator = samples.GetEnumerator();
        {
            if (enumerator.MoveNext())
            {
                n++;
                mean = enumerator.Current;
            }

            while (enumerator.MoveNext())
            {
                n++;
                mean += (enumerator.Current - mean) / n;
            }
        }
        return n != 0 ? mean : float.NaN;
    }

    //计算均值和标准差，均值和方差采用递推法，标准差采用牛顿法
    internal static (float, float) MeanStdValue(this IEnumerable<float> samples)
    {
        var mean = 0.0f;
        var variance = 0.0f; //方差
        var n = 0;
        using var enumerator = samples.GetEnumerator();
        {
            if (enumerator.MoveNext())
            {
                n++;
                mean = enumerator.Current;
            }

            while (enumerator.MoveNext())
            {
                n++;                
                var delta = enumerator.Current - mean;
                variance += delta * delta * (n - 1) / n;
                mean += delta / n;
            }
        }
        return (n != 0 ? mean : float.NaN, n > 1 ? SquareRootByNewton(variance / (n - 1)) : 0.0f);
    }

    //牛顿法计算平方根
    internal static float SquareRootByNewton(this float number)
    {
        if (number == 0)
        {
            return 0.0f;
        }
        var val = number; //最终           
        float deviation; //保存上一个计算的值,计算两者逼近差值            
        do
        {
            deviation = ((number / val) - val) / 2.0f; //newval-lastval
            val = (val + (number / val)) / 2.0f; //newval 
            deviation = deviation < 0 ? -deviation : deviation;
        } while (deviation > 0.0001f);

        return val;
    }

    //计算绝对值
    internal static float AbsValue(this float number) => number >= 0 ? number : -number;
}